package jofile

import (
	"github.com/pkg/errors"
	"os"
	"path"
)

const (
	FilePermNone        = 0000
	FilePermUserExOnly  = FilePermNone + 0100
	FilePermUserWrOnly  = FilePermNone + 0200
	FilePermUserRdOnly  = FilePermNone + 0400
	FilePermUserRdWr    = FilePermUserRdOnly | FilePermUserWrOnly
	FilePermUserAll     = FilePermUserExOnly | FilePermUserRdWr
	FilePermGroupExOnly = FilePermNone + 0010
	FilePermGroupWrOnly = FilePermNone + 0020
	FilePermGroupRdOnly = FilePermNone + 0040
	FilePermGroupRdWr   = FilePermGroupRdOnly | FilePermGroupWrOnly
	FilePermGroupAll    = FilePermGroupExOnly | FilePermGroupRdWr
	FilePermOtherExOnly = FilePermNone + 0001
	FilePermOtherWrOnly = FilePermNone + 0002
	FilePermOtherRdOnly = FilePermNone + 0004
	FilePermOtherRdWr   = FilePermOtherRdOnly | FilePermOtherWrOnly
	FilePermOtherAll    = FilePermOtherExOnly | FilePermOtherRdWr
	FilePermOsDef       = FilePermUserRdWr | FilePermGroupRdWr | FilePermOtherRdOnly
	FilePermAll         = FilePermUserAll | FilePermGroupAll | FilePermOtherAll
)

func MkdirForFile(filePath string) error {
	dirPath := path.Dir(filePath)
	return errors.Wrapf(os.MkdirAll(dirPath, FilePermAll), "try create dest dir '%s' for file '%s' fail",
		dirPath, filePath)
}

func OpenExclusiveFile(filePath string) (*os.File, error) {
	return os.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_EXCL, FilePermOsDef)
}

func OpenFileForAppend(filePath string) (*os.File, error) {
	if err := MkdirForFile(filePath); err != nil {
		return nil, errors.Wrapf(err, "try mkdir for file '%s' fail", filePath)
	}

	return os.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, FilePermOsDef)
}

func OpenFileForWrite(filePath string) (*os.File, error) {
	if err := MkdirForFile(filePath); err != nil {
		return nil, errors.Wrapf(err, "try mkdir for file '%s' fail", filePath)
	}

	return os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, FilePermOsDef)
}

func OpenFileForRead(filePath string) (*os.File, error) {
	return os.OpenFile(filePath, os.O_RDONLY, FilePermOsDef)
}

func WriteFile(filePath string, data []byte) error {
	if fi, err := OpenFileForWrite(filePath); err != nil {
		return errors.Wrapf(err, "try open file '%s' fail", filePath)
	} else {
		_, err = fi.Write(data)
		return errors.Wrapf(err, "try write file '%s' fail", filePath)
	}
}
